#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <regex>
#include <list>
#include <set>
#include "inp_to_cdb_convertor.h"

InpToCdbConvertor::InpToCdbConvertor() {
}

InpToCdbConvertor::~InpToCdbConvertor() {
}

int InpToCdbConvertor::convert(const std::string &inpPath, const std::string &cdbPath) {
    int parseResult = parseInpFile(inpPath);
    if (parseResult != 0) {
        return parseResult;
    }
    return generateCdbFile(cdbPath);
}

int InpToCdbConvertor::parseInpFile(const std::string& path) {
    std::list<std::string> ignoredLines;

    std::ifstream file(path);
    if (!file.is_open()) {
        std::cerr << "Error opening INP file: " << path << std::endl;
        return -1;
    }

    std::string line;
    std::string currentSection;
    std::string currentElemType;
    std::string currentNsetName;
    std::string currentMaterialName;
    std::map<std::string, std::string> parameters;
        
    while (getline(file, line)) {
        trim(line);
        if (line.empty()) continue;

        // 检测章节关键字
        if (line[0] == '*') {
            if (line[1] == '*') {
                ignoredLines.push_back(line);
                continue;
            }
            currentSection = getSectionType(line);
	    if (currentSection == "ELEMENT") {
                currentElemType = parseElemType(line);
            }
            if (currentSection == "NSET") {
                currentNsetName = parseNsetName(line);
            }
            if (currentSection == "MATERIAL") {
                currentMaterialName = parseMaterialName(line);
            }
	    parameters = getParamMap(line);
            continue;
        }

        // 解析数据
        if (currentSection == "NODE") {
            parseNode(line);
        } else if (currentSection == "ELEMENT") {
            parseElement(line, currentElemType);
        } else if (currentSection == "NSET") {
            parseNset(line, currentNsetName);
        } else if (currentSection == "ELSET") {
            parseElset(line, parameters);
        } else if (currentSection == "SOLID SECTION") {
            parseSolidSection(line, parameters);
        } else if (currentSection == "SHELL SECTION") {
            parseShellSection(line, parameters);
        } else if (currentSection == "CONDUCTIVITY") {
            parseConductivity(line, currentMaterialName);
        } else if (currentSection == "DENSITY") {
            parseDensity(line, currentMaterialName);
        } else if (currentSection == "ELASTIC") {
            parseElastic(line, currentMaterialName);
        } else if (currentSection == "EXPANSION") {
            parseExpansion(line, currentMaterialName);
        } else if (currentSection == "SPECIFIC HEAT") {
            parseSpecificHeat(line, currentMaterialName);
	} else if (currentSection == "BOUNDARY") {
            parseBoundary(line);
        } else if (currentSection == "DLOAD") {
            parseDload(line);
        }
    }

    return 0;
}

void InpToCdbConvertor::parseNode(const std::string& line) {
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() < 4) {
        return ;
    }

    Node tmpNode;
    tmpNode.id = std::stoi(tokens[0]);
    tmpNode.x = std::stod(tokens[1]);
    tmpNode.y = std::stod(tokens[2]);
    tmpNode.z = std::stod(tokens[3]);
    tmpNode.fromString = line;

    nodes.push_back(tmpNode);
}

std::string InpToCdbConvertor::parseElemType(const std::string& line) {
    std::string elemType;
    size_t typePos = line.find("type=");
    if (typePos != std::string::npos) {
        elemType = line.substr(typePos+5);
        elemType = elemType.substr(0, elemType.find_first_of(" \t\n"));
    }
    return elemType;
}

void InpToCdbConvertor::parseElement(const std::string &line, const std::string &elemType) {
    // C3D20
    if (elemType == "C3D20") {
        std::istringstream iss(line);
        std::vector<std::string> tokens;
        std::string token;

        while (std::getline(iss, token, ',')) {
            tokens.push_back(token);
        }
	if (tokens.size() > 21) {
            return;
        }
	else if (tokens.size() < 21) {
            if (!elements.empty() && elements.back().nodes.size() < 20 && elements.back().nodes.size() + tokens.size() == 20) {
                for (std::size_t i = 0; i < tokens.size(); i++) {
                    elements.back().nodes.push_back(std::stod(tokens[i]));
                }
                elements.back().fromString += line;
                return;
            }
	}

        if (tokens.size() < 2) {
            return ;
        }

        Element elem;
        elem.id = std::stoi(tokens[0]);
        elem.type = elemType;
        for (std::size_t i = 1; i < tokens.size(); i++) {
            elem.nodes.push_back(std::stod(tokens[i]));
        }
        elem.fromString = line;

        elements.push_back(elem);
    }
    else if (elemType == "S3" || elemType == "S4") {
        std::istringstream iss(line);
        std::vector<std::string> tokens;
        std::string token;

        while (std::getline(iss, token, ',')) {
            tokens.push_back(token);
        }
        
        if (elemType == "S3" && tokens.size() != 4) {
            return;
        }
        if (elemType == "S4" && tokens.size() != 5) {
            return;
        }
        Element elem;
        elem.id = std::stoi(tokens[0]);
        elem.type = elemType;
        for (std::size_t i = 1; i < tokens.size(); i++) {
            elem.nodes.push_back(std::stod(tokens[i]));
        }
        elem.fromString = line;

        elements.push_back(elem);
    }
}

std::string InpToCdbConvertor::parseNsetName(const std::string& line) {
    std::string nsetName;
    size_t namePos = line.find("nset=");
    if (namePos != std::string::npos) {
        nsetName = line.substr(namePos+5);
        nsetName = nsetName.substr(0, nsetName.find_first_of(" \t\n"));
    }
    return nsetName;
}

std::string InpToCdbConvertor::parseMaterialName(const std::string& line) {
    std::string materialName;
    size_t namePos = line.find("name=");
    if (namePos != std::string::npos) {
        materialName = line.substr(namePos+5);
        materialName = materialName.substr(0,materialName.find_first_of(" \t\n"));
    }
    
    return materialName;
}

void InpToCdbConvertor::parseNset(const std::string &line, const std::string &nsetName) {
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }
 
    for (auto &itemNset: nsets) {
        if (itemNset.nsetName == nsetName) {
            for (std::size_t i = 0; i < tokens.size(); i++) {
                itemNset.nodes.push_back(std::stod(tokens[i]));
            }
            return;
        }
    }

    Nset tmpNset;
    tmpNset.nsetName = nsetName;
    for (std::size_t i = 0; i < tokens.size(); i++) {
        tmpNset.nodes.push_back(std::stod(tokens[i]));
    }
    nsets.push_back(tmpNset);
    return;
}

void InpToCdbConvertor::parseElset(const std::string& line, std::map<std::string, std::string> parameters) {
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() < 3) {
        return ;
    }

    if (parameters.find("generate") != parameters.end()) {
        if (tokens.size() < 3) {
            return ;
        }
        Elset tmpElset;
        tmpElset.id = parameters["elset"];
        for (int i = std::stod(tokens[0]); i <= std::stod(tokens[1]); i += std::stod(tokens[2])) {
            tmpElset.elements.push_back(i);
        }
        elsets.push_back(tmpElset);
        return;
    }
    else {
        for (auto &itemElset: elsets) {
            if (itemElset.id == parameters["elset"]) {
                for (std::size_t i = 0; i < tokens.size(); i++) {
                    itemElset.elements.push_back(std::stod(tokens[i]));
                }
                return;
            }
        }
        
        Elset tmpElset;
        tmpElset.id = parameters["elset"];
        for (std::size_t i = 0; i < tokens.size(); i++) {
            tmpElset.elements.push_back(std::stod(tokens[i]));
        }
        elsets.push_back(tmpElset);
        return;
    }
}

void InpToCdbConvertor::parseSolidSection(const std::string& line, std::map<std::string, std::string> parameters) {
    SolidSection tmpSolidSection;
    tmpSolidSection.elsetId = parameters["elset"];
    tmpSolidSection.materialId = parameters["material"];
    solidSections.push_back(tmpSolidSection);
}

void InpToCdbConvertor::parseShellSection(const std::string& line, std::map<std::string, std::string> parameters) {
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;
    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() < 2) {
        return ;
    }

    ShellSection tmpShellSection;
    tmpShellSection.elsetId = parameters["elset"];
    tmpShellSection.materialId = parameters["material"];
    tmpShellSection.thickness = std::stod(tokens[0]);

    shellSections.push_back(tmpShellSection);
}

void InpToCdbConvertor::parseConductivity(const std::string &line, const std::string &materialName) { 
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() == 0 || tokens.size() > 2) {
        return ;
    }

    for (auto &itemMaterial:meterials) {
        if (itemMaterial.name == materialName) {
            if (tokens.size() == 1) {
                itemMaterial.conductivity =  std::stod(tokens[0]);
            }
            else {
                itemMaterial.conductivities[std::stod(tokens[1])] = std::stod(tokens[0]);
            }
            return;
        }
    }

    Meterial tmpMeterial;
    tmpMeterial.name = materialName;
    if (tokens.size() == 1) {
        tmpMeterial.conductivity =  std::stod(tokens[0]);
    }
    else {
        tmpMeterial.conductivities[std::stod(tokens[1])] = std::stod(tokens[0]);
    }
    meterials.push_back(tmpMeterial);
    return;
}

void InpToCdbConvertor::parseDensity(const std::string &line, const std::string &materialName) { 
    for (auto &itemMaterial:meterials) {
        if (itemMaterial.name == materialName) {
            itemMaterial.density = std::stod(line);
            return;
        }
    }

    Meterial tmpMeterial;
    tmpMeterial.name = materialName;
    tmpMeterial.density = std::stod(line);
    meterials.push_back(tmpMeterial);
    return;
}

void InpToCdbConvertor::parseElastic(const std::string &line, const std::string &materialName) { 
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() != 2) {
        return ;
    }

    for (auto &itemMaterial:meterials) {
        if (itemMaterial.name == materialName) {
            itemMaterial.elasticityModulus = std::stod(tokens[0]);
            itemMaterial.poissonRatio = std::stod(tokens[1]);
            return;
        }
    }

    Meterial tmpMeterial;
    tmpMeterial.elasticityModulus = std::stod(tokens[0]);
    tmpMeterial.poissonRatio = std::stod(tokens[1]);
    meterials.push_back(tmpMeterial);
    return;
}

void InpToCdbConvertor::parseExpansion(const std::string &line, const std::string &materialName) { 
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() == 0 || tokens.size() > 2) {
        return ;
    }

    for (auto &itemMaterial:meterials) {
        if (itemMaterial.name == materialName) {
            if (tokens.size() == 1) {
                itemMaterial.expansion =  std::stod(tokens[0]);
            }
            else {
                itemMaterial.expansions[std::stod(tokens[1])] = std::stod(tokens[0]);
            }
            return;
        }
    }

    Meterial tmpMeterial;
    tmpMeterial.name = materialName;
    if (tokens.size() == 1) {
        tmpMeterial.expansion =  std::stod(tokens[0]);
    }
    else {
        tmpMeterial.expansions[std::stod(tokens[1])] = std::stod(tokens[0]);
    }
    meterials.push_back(tmpMeterial);
    return;
}

void InpToCdbConvertor::parseSpecificHeat(const std::string &line, const std::string &materialName) { 
    for (auto &itemMaterial:meterials) {
        if (itemMaterial.name == materialName) {
            itemMaterial.specificHeat = std::stod(line);
            return;
        }
    }

    Meterial tmpMeterial;
    tmpMeterial.name = materialName;
    tmpMeterial.specificHeat = std::stod(line);
    meterials.push_back(tmpMeterial);
    return;
}

void InpToCdbConvertor::parseBoundary(const std::string &line) {
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() != 3) {
        return ;
    }
    
    Boundary tmpBoundary;
    tmpBoundary.nsetName = tokens[0];
    tmpBoundary.from = std::stoi(tokens[1]);
    tmpBoundary.to = std::stoi(tokens[2]);

    boundaries.push_back(tmpBoundary);
    return;
}

void InpToCdbConvertor::parseDload(const std::string &line) {
    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() < 5) {
        return ;
    }

    dload.nsetName = tokens[0];
    dload.dloadName = tokens[1];
    dload.xLoad = std::stod(tokens[2]);
    dload.yLoad = std::stod(tokens[3]);
    dload.zLoad = std::stod(tokens[4]);
}

int InpToCdbConvertor::generateCdbFile(const std::string& path) {
    std::ofstream file(path);
    if (!file.is_open()) {
        std::cerr << "Error creating CDB file: " << path << std::endl;
        return -1;
    }

    // 写入CDB头
    file << "/TITLE,CONVERTED_MODEL" << std::endl;
    file << "/PREP7" << std::endl;

    // 写入CDB 定义单元类型
    file << "ET,        1,186" << std::endl;
    file << "KEYOP,        1, 2,        1" << std::endl;
    file << "ET,        2,181" << std::endl;
    file << "KEYOP,        2, 3,        2" << std::endl;
    // file << "ET,        2,174" << std::endl;
    // file << "KEYOP,        2, 8,        2" << std::endl;
    // file << "KEYOP,        2, 9,        1" << std::endl;
    // file << "KEYOP,        2,12,        5" << std::endl;
    // file << "ET,        3,170" << std::endl;
    // file << "ET,        4,156" << std::endl;
    // file << "KEYOP,        4, 2,        1" << std::endl;
    // file << "KEYOP,        4, 5,        1" << std::endl;
    // file << "KEYOP,        4, 7,        1" << std::endl;

    // 写入节点
    file << "NBLOCK,6,SOLID," << std::setw(10) << nodes.size() << "," << std::setw(10) << nodes.size() << std::endl;
    file << "(3i9,6e21.13e3)" << std::endl;
    for (const auto& n : nodes) {
        std::ostringstream oss;
        oss << std::setw(9) << n.id << std::setw(9) << 0 << std::setw(9) << 0
            << std::scientific << std::uppercase << std::setprecision(13)
            << std::setw(21) << n.x
            << std::setw(21) << n.y
            << std::setw(21) << n.z
            << std::endl;
	file << oss.str();

        // std::cout << "Tracing: " << n.fromString << " -> " << oss.str();
    }
    file << "N,R5.3,LOC,       -1," << std::endl;

    // 写入单元
    file << "EBLOCK,19,SOLID," << std::setw(10) << elements.size() << "," << std::setw(10) << elements.size() << std::endl;
    file << "(19i9)" << std::endl;
    for (const auto& e : elements) {
        if (e.type == "C3D20") {
            std::string toString = ElementC3D20ToSOLID186(e);
            // std::cout << "Tracing: " << e.fromString << " -> " << toString;
	    file << toString;
        }
	else if (e.type == "S3" || e.type == "S4") {
            std::string toString = ElementS3_4ToSOLID181(e);
            // std::cout << "Tracing: " << e.fromString << " -> " << toString;
	    file << toString;
        }
    }
    file << "       -1" << std::endl;

    // 写入组件
    for (const auto &nset: nsets) {
        file << "CMBLOCK," << nset.nsetName << ",NODE," << std::setw(8) << nset.nodes.size() << std::endl;
	file << "(8i10)" << std::endl;
        for (std::size_t i = 0; i < nset.nodes.size(); i++) {
            if (i != 0 && i % 8 == 0) {
                file << std::endl;
            }
            file << std::setw(10) << nset.nodes[i];
        }
        file << std::endl;
    }

    // 写入材料
    for (std::size_t i = 0; i < meterials.size(); i++) {
        // 弹性模量
        if (meterials[i].elasticityModulus > 0.0) {
            file << "MPTEMP,R5.0, 1, 1,  0.00000000    ," << std::endl;
            file << "MPDATA,R5.0, 1,EX  ," << std::setw(8) << i + 1 << ", 1," << std::setw(16) << meterials[i].elasticityModulus << "," << std::endl;
        }
        // 泊松比
        if (meterials[i].poissonRatio > 0.0) {
            file << "MPTEMP,R5.0, 1, 1,  0.00000000    ," << std::endl;
            file << "MPDATA,R5.0, 1,NUXY," << std::setw(8) << i + 1 << ", 1," << std::setw(16) << meterials[i].poissonRatio << "," << std::endl;
        }
        // 膨胀系数
        if (meterials[i].expansions.size() > 0) {
            int index = 0;
            std::ostringstream ossTemp;
            std::ostringstream ossExpansion;
            for (const auto &itemExpansion: meterials[i].expansions) {
                if (index % 3 == 0) {
                    if (index != 0) {
                        ossTemp << std::endl;
                        ossExpansion << std::endl;
                    }
                    ossTemp << "MPTEMP,R5.0," << std::setw(2) <<  meterials[i].expansions.size() << "," << std::setw(2) << index + 1;
                    ossExpansion << "MPDATA,R5.0," << std::setw(2) <<  meterials[i].expansions.size() << ",ALPX," << std::setw(8) << i + 1 << "," << std::setw(2) << index + 1;
                }
                ossTemp << "," << std::setw(16) << itemExpansion.first;
                ossExpansion << "," << std::setw(16) << itemExpansion.second;
                index++;
            }
            ossTemp << ",";
            ossExpansion << ",";
            file << ossTemp.str() << std::endl << ossExpansion.str() << std::endl;
        }
	else if (meterials[i].expansion > 0.0) {
            file << "MPTEMP,R5.0, 1, 1,  0.00000000    ," << std::endl;
            file << "MPDATA,R5.0, 1,ALPX," << std::setw(8) << i + 1 << ", 1," << std::setw(16) << meterials[i].expansion << "," << std::endl;
        }
        // 密度
        if (meterials[i].density > 0.0) {
            file << "MPTEMP,R5.0, 1, 1,  0.00000000    ," << std::endl;
            file << "MPDATA,R5.0, 1,DENS," << std::setw(8) << i + 1 << ", 1," << std::setw(16) << meterials[i].density << "," << std::endl;
        }
        // 导电性
        if (meterials[i].conductivities.size() > 0) {
            int index = 0;
            std::ostringstream ossTemp;
            std::ostringstream ossConductivity;
            for (const auto &itemConductivity: meterials[i].conductivities) {
                if (index % 3 == 0) {
                    if (index != 0) {
                        ossTemp << std::endl;
                        ossConductivity << std::endl;
                    }
                    ossTemp << "MPTEMP,R5.0," << std::setw(2) <<  meterials[i].conductivities.size() << "," << std::setw(2) << index + 1;
                    ossConductivity << "MPDATA,R5.0," << std::setw(2) <<  meterials[i].conductivities.size() << ",KXX ," << std::setw(8) << i + 1 << "," << std::setw(2) << index + 1;
                }
                ossTemp << "," << std::setw(16) << itemConductivity.first;
                ossConductivity << "," << std::setw(16) << itemConductivity.second;
                index++;
            }
            ossTemp << ",";
            ossConductivity << ",";
            file << ossTemp.str() << std::endl << ossConductivity.str() << std::endl;
        }
	else if (meterials[i].conductivity > 0.0) {
            file << "MPTEMP,R5.0, 1, 1,  0.00000000    ," << std::endl;
            file << "MPDATA,R5.0, 1,KXX ," << std::setw(8) << i + 1 << ", 1," << std::setw(16) << meterials[i].conductivity << "," << std::endl;
        }
        // 比热容
        if (meterials[i].specificHeat > 0.0) {
            file << "MPTEMP,R5.0, 1, 1,  0.00000000    ," << std::endl;
            file << "MPDATA,R5.0, 1,C   ," << std::setw(8) << i + 1 << ", 1," << std::setw(16) << meterials[i].specificHeat << "," << std::endl;
        }
    }

    file << "EXTOPT,ATTR,      0,      0,      0" << std::endl;
    file << "EXTOPT,ESIZE,  0,  0.0000" << std::endl;
    file << "EXTOPT,ACLEAR,      0" << std::endl;
    file << "TREF,  22.0000000" << std::endl;
    file << "IRLF,  0" << std::endl;
    file << "BFUNIF,TEMP,_TINY" << std::endl;
    file << "ACEL," << dload.xLoad << "," << dload.yLoad << "," << dload.zLoad << std::endl;
    file << "OMEGA,  0.00000000    ,  0.00000000    ,  0.00000000" << std::endl;
    file << "DOMEGA,  0.00000000    ,  0.00000000    ,  0.00000000" << std::endl;
    file << "CGLOC,  0.00000000    ,  0.00000000    ,  0.00000000" << std::endl;
    file << "CGOMEGA,  0.00000000    ,  0.00000000    ,  0.00000000" << std::endl;
    file << "DCGOMG,  0.00000000    ,  0.00000000    ,  0.00000000" << std::endl;
    file << std::endl;

    file << "NSUBST,         1,         1,         1," << std::endl;
    file << "KUSE,     0" << std::endl;
    file << "TIME,  1.00000000" << std::endl;
    file << "ALPHAD,  0.00000000" << std::endl;
    file << "BETAD,  0.00000000" << std::endl;
    file << "DMPRAT,  0.00000000" << std::endl;
    file << "DMPSTR,  0.00000000" << std::endl;
    file << std::endl;
    
    file << "CRPLIM, 0.100000000    ,   0" << std::endl;
    file << "CRPLIM,  0.00000000    ,   1" << std::endl;
    file << "NCNV,     1,  0.00000000    ,     0,  0.00000000    ,  0.00000000" << std::endl;
    file << std::endl;

    file << "NEQIT,     1,FORC" << std::endl;
    file << "PRED,OFF ,,OFF" << std::endl;
    file << "ERESX,DEFA" << std::endl;
    file << "OUTRES, ALL,NONE," << std::endl;
    file << "OUTRES,NSOL, ALL," << std::endl;
    file << "OUTRES,RSOL, ALL," << std::endl;
    file << "OUTRES,STRS, ALL," << std::endl;
    file << "OUTRES,EPEL, ALL," << std::endl;
    file << "OUTRES,EPPL, ALL," << std::endl;
    file << std::endl;

    // 写入边界条件
    std::set<std::string> nBoundarySetNames;
    for (const auto &itemBoundary: boundaries) {
        nBoundarySetNames.insert(itemBoundary.nsetName);
    }
    for (const auto &itemBoundarySetName: nBoundarySetNames) {
        for (const auto &itemNset: nsets) {
            if (itemBoundarySetName == itemNset.nsetName) {
                for (const auto &nodeId: itemNset.nodes) {
                    file << "D," << std::setw(7) << nodeId << ",UX  ,  0.00000000    ,  0.00000000" << std::endl;
                    file << "D," << std::setw(7) << nodeId << ",UY  ,  0.00000000    ,  0.00000000" << std::endl;
                    file << "D," << std::setw(7) << nodeId << ",UZ  ,  0.00000000    ,  0.00000000" << std::endl;
                }
            }
	}
    }

    file <<"/GO" << std::endl;
    file << "FINISH" << std::endl;
    return 0;
}

std::string InpToCdbConvertor::ElementC3D20ToSOLID186(const Element &elem) {
    // 查找材料号
    std::size_t meterialId = 0;
    for (const auto &itemElset: elsets) {
        for (const auto &itemElsetElement: itemElset.elements) {
            if (elem.id == itemElsetElement) {
                for (const auto &itemSolidSection: solidSections) {
                    if (itemElset.id == itemSolidSection.elsetId) {
                        for (std::size_t i = 0; i < meterials.size(); i++) {
                            if (meterials[i].name == itemSolidSection.materialId) {
                                meterialId = i + 1;
                                break;
                            }
                        }
                        break;
                    }
                }
                break;
            }
	}
    }
   
    std::ostringstream oss;
    oss << std::setw(9) << meterialId;
    oss << "        1        1        1        0        0        0        0       20        0";
    oss << std::setw(9) << elem.id;
    for (size_t i = 0; i < elem.nodes.size(); ++i) {
        if (i==8) {
            oss << std::endl;
        }
        oss << std::setw(9) << elem.nodes[i];
    }
    oss << std::endl;
    return oss.str();
}

std::string InpToCdbConvertor::ElementS3_4ToSOLID181(const Element &elem) {
    // 查找材料号
    std::size_t meterialId = 0;
    for (const auto &itemElset: elsets) {
        for (const auto &itemElsetElement: itemElset.elements) {
            if (elem.id == itemElsetElement) {
                for (const auto &itemShellSection: shellSections) {
                    if (itemElset.id == itemShellSection.elsetId) {
                        for (std::size_t i = 0; i < meterials.size(); i++) {
                            if (meterials[i].name == itemShellSection.materialId) {
                                meterialId = i + 1;
                                break;
                            }
                        }
                        break;
                    }
                }
                break;
            }
        }
    }

    std::ostringstream oss;
    oss << std::setw(9) << meterialId;
    oss << "        2        1        1        0        0        0        0        4        0";
    oss << std::setw(9) << elem.id;
    for (size_t i = 0; i < elem.nodes.size(); ++i) {
        oss << std::setw(9) << elem.nodes[i];
    }
    if (elem.nodes.size() == 3) {
        oss << std::setw(9) << elem.nodes[2];
    }
    oss << std::endl;
    return oss.str();
}

std::string InpToCdbConvertor::getSectionType(const std::string& line) {
    std::string keyword = line;
    auto comma_position = line.find(",");
    if (line.find(",") != std::string::npos) {
        keyword = line.substr(0,comma_position);
    }
    if (keyword.find("NODE") != std::string::npos || keyword.find("Node") != std::string::npos || keyword.find("node") != std::string::npos) {
        return "NODE";
    }
    if (keyword.find("ELEMENT") != std::string::npos || keyword.find("Element") != std::string::npos || keyword.find("element") != std::string::npos) {
        return "ELEMENT";
    }
    if (keyword.find("ELSET") != std::string::npos || keyword.find("Elset") != std::string::npos || keyword.find("elset") != std::string::npos) {
        return "ELSET";
    }
    if (keyword.find("SOLID SECTION") != std::string::npos || keyword.find("Solid Section") != std::string::npos || keyword.find("solid section") != std::string::npos) {
        return "SOLID SECTION";
    }
    if (keyword.find("SHELL SECTION") != std::string::npos || keyword.find("Shell Section") != std::string::npos || keyword.find("shell section") != std::string::npos) {
        return "SHELL SECTION";
    }
    if (keyword.find("NSET") != std::string::npos || keyword.find("Nset") != std::string::npos || keyword.find("nset") != std::string::npos) {
        return "NSET";
    }
    if (keyword.find("MATERIAL") != std::string::npos || keyword.find("Material") != std::string::npos || keyword.find("material") != std::string::npos) {
        return "MATERIAL";
    }
    if (keyword.find("CONDUCTIVITY") != std::string::npos || keyword.find("Conductivity") != std::string::npos || keyword.find("conductivity") != std::string::npos) {
        return "CONDUCTIVITY";
    }
    if (keyword.find("DENSITY") != std::string::npos || keyword.find("Density") != std::string::npos || keyword.find("density") != std::string::npos) {
        return "DENSITY";
    }
    if (keyword.find("ELASTIC") != std::string::npos || keyword.find("Elastic") != std::string::npos || keyword.find("elastic") != std::string::npos) {
        return "ELASTIC";
    }
    if (keyword.find("EXPANSION") != std::string::npos || keyword.find("Expansion") != std::string::npos || keyword.find("expansion") != std::string::npos) {
        return "EXPANSION";
    }
    if (keyword.find("SPECIFIC HEAT") != std::string::npos || keyword.find("Specific Heat") != std::string::npos || keyword.find("specific heat") != std::string::npos) {
        return "SPECIFIC HEAT";
    }
    if (keyword.find("BOUNDARY") != std::string::npos || keyword.find("Boundary") != std::string::npos || keyword.find("boundary") != std::string::npos) {
        return "BOUNDARY";
    }
    if (keyword.find("DLOAD") != std::string::npos || keyword.find("Dload") != std::string::npos || keyword.find("dload") != std::string::npos) {
        return "DLOAD";
    }
    return "OTHER";
}

void InpToCdbConvertor::trim(std::string& s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
        return !std::isspace(ch);
    }));
    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
        return !std::isspace(ch);
    }).base(), s.end());
}

std::map<std::string, std::string> InpToCdbConvertor::getParamMap(const std::string& line) {
    std::map<std::string, std::string> result;

    std::istringstream iss(line);
    std::vector<std::string> tokens;
    std::string token;

    // 分割字段
    while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
    }

    if (tokens.size() < 2) {
        return result;
    }

    for (std::size_t i = 1; i < tokens.size(); i++) {
        auto posEqual = tokens[i].find("=");
        if (posEqual == std::string::npos) {
            std::string key = tokens[i];
            trim(key);
            result[key] = "";
        }
        else {
            std::string key = tokens[i].substr(0, posEqual);
            std::string value = tokens[i].substr(posEqual + 1);
            trim(key);
            trim(value);
            result[key] = value; 
        }
    }
    return result;
}

int InpToCdbConvertor::extractTrailingDigits(const std::string& str) {
    auto it = std::find_if_not(str.rbegin(), str.rend(), [](char c) {
        return std::isdigit(static_cast<unsigned char>(c));
    });
    std::string result = std::string(it.base(), str.end());
    if (result.empty()) {
        return 0;
    }
    
    return std::stoi(result);
}



